package com.company.loganalyzer.tools.impl;

import com.company.loganalyzer.config.ElasticsearchConfig;
import com.company.loganalyzer.dto.ToolInput;
import com.company.loganalyzer.dto.ToolResult;
import com.company.loganalyzer.model.LogEntry;
import com.company.loganalyzer.tools.LogAnalysisTool;
import com.company.loganalyzer.utils.TimeRangeUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.*;

/**
 * 错误分析工具
 * 
 * 对应Python版本的analyze_errors函数
 * 分析错误日志的模式、趋势和根本原因
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class ErrorAnalysisTool implements LogAnalysisTool {

    private final ElasticsearchOperations elasticsearchOperations;
    private final ElasticsearchConfig elasticsearchConfig;

    // Java常见异常类型
    private static final Map<String, String> EXCEPTION_PATTERNS = Map.of(
        "NullPointerException", "空指针异常",
        "IllegalArgumentException", "非法参数异常",
        "IllegalStateException", "非法状态异常",
        "IndexOutOfBoundsException", "数组越界异常",
        "ClassCastException", "类型转换异常",
        "ConcurrentModificationException", "并发修改异常",
        "TimeoutException", "超时异常",
        "ConnectException", "连接异常",
        "SQLException", "数据库异常",
        "IOException", "IO异常",
        "OutOfMemoryError", "内存溢出错误",
        "StackOverflowError", "栈溢出错误"
    );

    @Override
    public String getName() {
        return "analyze_errors";
    }

    @Override
    public String getDescription() {
        return "分析错误日志，识别错误模式、统计错误频率、分析根本原因并提供修复建议";
    }

    @Override
    public String[] getSupportedParameters() {
        return new String[]{"timeRange", "serviceName", "limit"};
    }

    @Override
    public boolean canHandle(ToolInput input) {
        // 检查是否包含错误分析相关的查询词
        String query = input.getQuery();
        return (query != null && (query.contains("错误") || query.contains("异常") || 
                query.contains("error") || query.contains("exception") || query.contains("分析"))) ||
               input.getLevel() != null && Arrays.asList("ERROR", "FATAL", "CRITICAL").contains(input.getLevel().toUpperCase());
    }

    @Override
    public int getPriority() {
        return 20; // 中等优先级
    }

    @Override
    public Mono<ToolResult> execute(ToolInput input) {
        return Mono.fromCallable(() -> {
            long startTime = System.currentTimeMillis();
            
            try {
                // 构建错误日志查询
                NativeSearchQuery searchQuery = buildErrorQuery(input);
                
                // 设置索引名称
                List<String> indexNames = TimeRangeUtils.generateIndexNames(
                    elasticsearchConfig.getIndexPattern(), 
                    input.getTimeRange()
                );
                
                // 执行搜索
                SearchHits<LogEntry> searchHits = elasticsearchOperations.search(
                    searchQuery, 
                    LogEntry.class,
                    indexNames.toArray(new String[0])
                );
                
                // 处理结果
                List<LogEntry> errorLogs = searchHits.getSearchHits().stream()
                    .map(SearchHit::getContent)
                    .collect(Collectors.toList());
                
                // 错误分析
                Map<String, Object> errorAnalysis = performErrorAnalysis(errorLogs);
                
                // 构建返回结果
                Map<String, Object> result = new HashMap<>();
                result.put("timeRange", input.getTimeRange());
                result.put("serviceName", input.getServiceName());
                result.put("totalErrors", searchHits.getTotalHits());
                result.put("analyzedErrors", errorLogs.size());
                result.put("errorAnalysis", errorAnalysis);
                result.put("topErrors", errorLogs.stream().limit(10).collect(Collectors.toList()));
                result.put("indexNames", indexNames);
                
                long executionTime = System.currentTimeMillis() - startTime;
                
                log.info("错误分析完成 - 时间范围: {}, 服务: {}, 错误数: {}, 耗时: {}ms", 
                    input.getTimeRange(), input.getServiceName(), errorLogs.size(), executionTime);
                
                ToolResult toolResult = ToolResult.success(getName(), result, "错误分析完成");
                toolResult.setExecutionTime(executionTime);
                return toolResult;
                
            } catch (Exception e) {
                log.error("错误分析失败", e);
                return ToolResult.error(getName(), "错误分析失败: " + e.getMessage(), e);
            }
        });
    }

    /**
     * 构建错误日志查询
     */
    private NativeSearchQuery buildErrorQuery(ToolInput input) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        
        var boolQuery = boolQuery();
        
        // 过滤错误级别
        boolQuery.filter(termsQuery("level", "ERROR", "FATAL", "CRITICAL"));
        
        // 服务名过滤
        if (input.getServiceName() != null && !input.getServiceName().trim().isEmpty()) {
            boolQuery.filter(termQuery("serviceName", input.getServiceName()));
        }
        
        // 时间范围过滤
        if (input.getTimeRange() != null) {
            LocalDateTime[] timeRange = TimeRangeUtils.parseTimeRange(input.getTimeRange());
            boolQuery.filter(rangeQuery("timestamp")
                .gte(timeRange[0])
                .lte(timeRange[1]));
        }
        
        queryBuilder.withQuery(boolQuery);
        
        // 排序 - 按时间倒序
        queryBuilder.withSort(Sort.by(Sort.Direction.DESC, "timestamp"));
        
        // 分页 - 限制最大2000条进行分析
        int limit = input.getLimit() != null ? input.getLimit() : 2000;
        Pageable pageable = PageRequest.of(0, Math.min(limit, 2000));
        queryBuilder.withPageable(pageable);
        
        return queryBuilder.build();
    }

    /**
     * 执行错误分析
     */
    private Map<String, Object> performErrorAnalysis(List<LogEntry> errorLogs) {
        Map<String, Object> analysis = new HashMap<>();
        
        if (errorLogs.isEmpty()) {
            analysis.put("message", "未找到错误日志");
            return analysis;
        }
        
        // 1. 错误类型统计
        Map<String, Object> errorTypes = analyzeErrorTypes(errorLogs);
        analysis.put("errorTypes", errorTypes);
        
        // 2. 服务错误分布
        Map<String, Long> serviceErrors = errorLogs.stream()
            .collect(Collectors.groupingBy(
                log -> log.getServiceName() != null ? log.getServiceName() : "UNKNOWN",
                Collectors.counting()
            ));
        analysis.put("serviceErrors", serviceErrors);
        
        // 3. 异常模式分析
        Map<String, Object> exceptionPatterns = analyzeExceptionPatterns(errorLogs);
        analysis.put("exceptionPatterns", exceptionPatterns);
        
        // 4. 时间趋势分析
        Map<String, Object> timeTrends = analyzeTimeTrends(errorLogs);
        analysis.put("timeTrends", timeTrends);
        
        // 5. 根本原因分析
        List<String> rootCauses = analyzeRootCauses(errorLogs);
        analysis.put("rootCauses", rootCauses);
        
        // 6. 修复建议
        List<String> suggestions = generateSuggestions(errorLogs, errorTypes);
        analysis.put("suggestions", suggestions);
        
        // 7. 统计信息
        analysis.put("totalErrors", errorLogs.size());
        analysis.put("affectedServices", serviceErrors.size());
        analysis.put("topServices", serviceErrors.entrySet().stream()
            .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
            .limit(5)
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (e1, e2) -> e1,
                LinkedHashMap::new
            )));
        
        return analysis;
    }

    /**
     * 分析错误类型
     */
    private Map<String, Object> analyzeErrorTypes(List<LogEntry> errorLogs) {
        Map<String, Integer> typeCount = new HashMap<>();
        
        for (LogEntry log : errorLogs) {
            String message = log.getMessage();
            String exception = log.getException();
            String text = (message != null ? message : "") + " " + (exception != null ? exception : "");
            
            // 检查Java常见异常
            boolean foundType = false;
            for (Map.Entry<String, String> entry : EXCEPTION_PATTERNS.entrySet()) {
                if (text.contains(entry.getKey())) {
                    typeCount.merge(entry.getValue(), 1, Integer::sum);
                    foundType = true;
                }
            }
            
            // 自定义异常检查
            if (!foundType) {
                if (text.contains("Timeout") || text.contains("超时")) {
                    typeCount.merge("超时异常", 1, Integer::sum);
                } else if (text.contains("Connection") || text.contains("连接")) {
                    typeCount.merge("连接异常", 1, Integer::sum);
                } else if (text.contains("Permission") || text.contains("权限")) {
                    typeCount.merge("权限异常", 1, Integer::sum);
                } else if (text.contains("Validation") || text.contains("验证")) {
                    typeCount.merge("验证异常", 1, Integer::sum);
                } else {
                    typeCount.merge("其他异常", 1, Integer::sum);
                }
            }
        }
        
        Map<String, Object> result = new HashMap<>();
        result.put("distribution", typeCount);
        result.put("topTypes", typeCount.entrySet().stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
            .limit(5)
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (e1, e2) -> e1,
                LinkedHashMap::new
            )));
        
        return result;
    }

    /**
     * 分析异常模式
     */
    private Map<String, Object> analyzeExceptionPatterns(List<LogEntry> errorLogs) {
        Map<String, Integer> patterns = new HashMap<>();
        Set<String> uniqueStackTraces = new HashSet<>();
        
        Pattern exceptionPattern = Pattern.compile("([a-zA-Z]+Exception|[a-zA-Z]+Error)");
        
        for (LogEntry log : errorLogs) {
            String exception = log.getException();
            if (exception != null && !exception.trim().isEmpty()) {
                // 提取异常类型
                Matcher matcher = exceptionPattern.matcher(exception);
                while (matcher.find()) {
                    patterns.merge(matcher.group(1), 1, Integer::sum);
                }
                
                // 统计唯一堆栈跟踪
                uniqueStackTraces.add(exception.substring(0, Math.min(exception.length(), 200)));
            }
        }
        
        Map<String, Object> result = new HashMap<>();
        result.put("exceptionTypes", patterns);
        result.put("uniqueStackTraces", uniqueStackTraces.size());
        result.put("totalExceptions", patterns.values().stream().mapToInt(Integer::intValue).sum());
        
        return result;
    }

    /**
     * 分析时间趋势
     */
    private Map<String, Object> analyzeTimeTrends(List<LogEntry> errorLogs) {
        Map<String, Long> hourlyDistribution = errorLogs.stream()
            .collect(Collectors.groupingBy(
                log -> log.getTimestamp().getHour() + ":00",
                Collectors.counting()
            ));
        
        Map<String, Object> result = new HashMap<>();
        result.put("hourlyDistribution", hourlyDistribution);
        
        if (!errorLogs.isEmpty()) {
            LocalDateTime firstError = errorLogs.get(errorLogs.size() - 1).getTimestamp();
            LocalDateTime lastError = errorLogs.get(0).getTimestamp();
            result.put("timeSpan", Map.of(
                "start", firstError.toString(),
                "end", lastError.toString(),
                "duration", java.time.Duration.between(firstError, lastError).toMinutes() + " minutes"
            ));
        }
        
        return result;
    }

    /**
     * 分析根本原因
     */
    private List<String> analyzeRootCauses(List<LogEntry> errorLogs) {
        List<String> rootCauses = new ArrayList<>();
        
        // 统计异常关键词
        Map<String, Integer> keywords = new HashMap<>();
        for (LogEntry log : errorLogs) {
            String text = (log.getMessage() != null ? log.getMessage() : "") + 
                         " " + (log.getException() != null ? log.getException() : "");
            
            if (text.contains("NullPointerException")) {
                keywords.merge("空值检查缺失", 1, Integer::sum);
            }
            if (text.contains("ConnectionException") || text.contains("ConnectTimeoutException")) {
                keywords.merge("网络连接问题", 1, Integer::sum);
            }
            if (text.contains("SQLException")) {
                keywords.merge("数据库访问问题", 1, Integer::sum);
            }
            if (text.contains("OutOfMemoryError")) {
                keywords.merge("内存不足", 1, Integer::sum);
            }
        }
        
        // 根据频率生成根本原因
        keywords.entrySet().stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
            .limit(5)
            .forEach(entry -> rootCauses.add(entry.getKey() + " (出现" + entry.getValue() + "次)"));
        
        if (rootCauses.isEmpty()) {
            rootCauses.add("需要进一步分析具体错误信息");
        }
        
        return rootCauses;
    }

    /**
     * 生成修复建议
     */
    private List<String> generateSuggestions(List<LogEntry> errorLogs, Map<String, Object> errorTypes) {
        List<String> suggestions = new ArrayList<>();
        
        @SuppressWarnings("unchecked")
        Map<String, Integer> types = (Map<String, Integer>) errorTypes.get("distribution");
        
        if (types.containsKey("空指针异常")) {
            suggestions.add("增加空值检查：在使用对象前进行null检查，使用Optional类处理可能为空的值");
        }
        
        if (types.containsKey("连接异常") || types.containsKey("超时异常")) {
            suggestions.add("优化连接配置：增加连接池大小，设置合理的超时时间，实现重试机制");
        }
        
        if (types.containsKey("数据库异常")) {
            suggestions.add("数据库优化：检查SQL语句性能，优化数据库连接池配置，添加事务处理");
        }
        
        if (types.containsKey("内存溢出错误")) {
            suggestions.add("内存管理：增加JVM堆内存，优化对象创建，添加内存监控");
        }
        
        if (types.containsKey("并发修改异常")) {
            suggestions.add("并发控制：使用线程安全的集合类，添加同步机制，避免并发修改");
        }
        
        // 通用建议
        suggestions.add("加强错误处理：添加try-catch块，记录详细的错误日志");
        suggestions.add("增加监控告警：设置错误率阈值告警，建立实时监控");
        suggestions.add("代码审查：进行代码审查，遵循最佳实践，添加单元测试");
        
        return suggestions;
    }
}